/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-15 18:02:40
 * @Description  : 用户-部门接口参数验证模型
 */
const Joi = require('joi')
const R = require('@/models/Response')
const { ERROR_USER_CODE, ERROR_SYSTEM_CODE } = require('@/constants/errorCode')
const {
  IS_INTEGER,
  IS_UNSAFE_INTEGER,
  IS_UNSAFE_INTEGER_2
} = require('@/constants/joiSchema')
const { pwdArr, userReg } = require('@/constants/validateReg')
const { config } = require('@/config/system')
const { effect } = require('@/config/reactive')
const { dumpCheck } = require('@/utils/dumpCheck')
const { User, UserDepartment } = require('@/models/model')
const { compareRole } = require('@/utils/common')
const { Op } = require('sequelize')

const userDepSchema = {
  userDepIds: Joi.array().items(IS_UNSAFE_INTEGER),
  userId: IS_UNSAFE_INTEGER,
  userIds: Joi.array().items(IS_UNSAFE_INTEGER),
  sizeMax: IS_UNSAFE_INTEGER_2.min(0),
  username: Joi.string().pattern(userReg),
  password: Joi.string().pattern(pwdArr[0]),
  email: Joi.string().email().allow('', null),
  nickname: Joi.string().min(2).max(50).allow('', null),
  phone: Joi.string().length(11).allow('', null),
  avator: Joi.string().allow('', null),
  sex: IS_INTEGER.valid(0, 1),
  roleId: IS_UNSAFE_INTEGER,
  departmentId: IS_UNSAFE_INTEGER,
  departments: Joi.array().items(
    Joi.object({
      departmentId: IS_UNSAFE_INTEGER,
      roleId: IS_UNSAFE_INTEGER,
      sizeMax: IS_UNSAFE_INTEGER_2.min(-1)
    })
  )
}

const initUserDepSchema = () => {
  userDepSchema.sizeMax = IS_UNSAFE_INTEGER_2.min(0).max(
    Number(config.defaultSizeMax)
  )

  userDepSchema.departments = Joi.array().items(
    Joi.object({
      departmentId: IS_UNSAFE_INTEGER.required(),
      roleId: IS_UNSAFE_INTEGER.required(),
      sizeMax: IS_UNSAFE_INTEGER_2.min(0)
        .max(Number(config.defaultSizeMax))
        .required()
    })
  )

  userDepSchema.password = Joi.string().pattern(pwdArr[config.pwdLevel])
}
effect(initUserDepSchema)

/**
 * @description 部门添加用户的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.createUserToDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    username: userDepSchema.username.required(),
    nickname: userDepSchema.nickname,
    password: Joi.string().pattern(pwdArr[0]),
    sizeMax: userDepSchema.sizeMax,
    sex: userDepSchema.sex,
    email: userDepSchema.email,
    phone: userDepSchema.phone,
    roleId: userDepSchema.roleId.required(),
    departments: userDepSchema.departments.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { username, roleId, departments } = ctx.request.body

  // 验证用户名的合法性
  const b = await dumpCheck.checkUsername(ctx, username)
  if (!b) {
    return
  }

  // 验证角色ID的合法性,存在且可见,且为系统角色
  const b2 = await dumpCheck.checkRoleIds([roleId], true, false, 0)
  if (!b2) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  const curUserRole = await User.findByPk(BigInt(ctx.user.id))
  const b6 = await compareRole(roleId, curUserRole.roleId)
  if (!b6) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  // 验证部门ID的合法性
  const b3 = await dumpCheck.checkDepPids(
    departments.map((item) => item.departmentId),
    false
  )
  if (!b3) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 验证对应的在部门设置的角色的合法性
  const b4 = await dumpCheck.checkRoleIds(
    [...new Set(departments.map((item) => item.roleId))],
    true,
    false,
    1
  )
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  // 到这里说明可以进行用户的添加，和用户-部门记录的添加
  await next()
}

/**
 * @description 部门更新用户的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.updateUserToDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    userId: userDepSchema.userId.required(),
    username: userDepSchema.username.required(),
    nickname: userDepSchema.nickname,
    password: Joi.string().pattern(pwdArr[0]).allow('', null),
    sizeMax: userDepSchema.sizeMax,
    sex: userDepSchema.sex,
    email: userDepSchema.email,
    phone: userDepSchema.phone,
    roleId: userDepSchema.roleId.required(),
    departments: userDepSchema.departments.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { roleId, departments, userId } = ctx.request.body

  // 验证用户ID的合法性
  const b = await dumpCheck.checkUserIds([userId])
  if (!b) {
    ctx.body = R.error(ERROR_USER_CODE.USER_ID_ERROR)
    return
  }

  // 需要用户的系统权限小于当前操作者的权限，才可继续
  // 验证userIds的合法性
  const curUser = await User.findByPk(BigInt(ctx.user.id))

  const user = await User.findByPk(BigInt(userId))
  const res = await compareRole(user.roleId, curUser.roleId)
  if (!res) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
    return
  }

  // 验证角色ID的合法性,存在且可见,且为系统角色
  const b2 = await dumpCheck.checkRoleIds([roleId], true, false, 0)
  if (!b2) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  const curUserRole = await User.findByPk(BigInt(ctx.user.id))
  const b6 = await compareRole(roleId, curUserRole.roleId)
  if (!b6) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  // 验证部门ID的合法性
  const b3 = await dumpCheck.checkDepPids(
    departments.map((item) => item.departmentId),
    false
  )
  if (!b3) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 验证对应的在部门设置的角色的合法性
  const b4 = await dumpCheck.checkRoleIds(
    [...new Set(departments.map((item) => item.roleId))],
    true,
    false,
    1
  )
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  // 到这里说明可以进行用户的更新，和用户-部门记录的更新
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 迁移用户到其他部门的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.moveUserToDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    curDepId: userDepSchema.departmentId.required(),
    userIds: userDepSchema.userIds.required(),
    departmentId: userDepSchema.departmentId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { userIds, departmentId, curDepId } = ctx.request.body

  const userDeps = await UserDepartment.findAll({
    where: {
      departmentId: BigInt(curDepId),
      userId: {
        [Op.in]: userIds
      }
    }
  })

  const userDepIds = userDeps.map((item) => item.id)

  // 要想迁移用户到其他部门，首先得存在当前得用户-部门记录
  // 验证用户-ID数组的合法性
  const b = await dumpCheck.checkUserDepIds(userDepIds)
  if (!b) {
    ctx.body = R.error(ERROR_USER_CODE.USER_DEP_ID_ERROR)
    return
  }

  // 验证目标部门的合法性
  const b2 = await dumpCheck.checkDepPids([departmentId], false)
  if (!b2) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 到这里说明参数没有问题
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 添加已经存在的用户到其他部门
 * @param {*} ctx
 * @param {*} next
 */
module.exports.copyUserToDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    userIds: userDepSchema.userIds.required(),
    departments: userDepSchema.departments.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { userIds, departments } = ctx.request.body
  // 验证用户ID的合法性
  const b = await dumpCheck.checkUserIds(userIds)
  if (!b) {
    ctx.body = R.error(ERROR_USER_CODE.USER_ID_ERROR)
    return
  }

  // 验证userIds的合法性
  const curUser = await User.findByPk(BigInt(ctx.user.id))
  for (let i = 0; i < userIds.length; i++) {
    const user = await User.findByPk(BigInt(userIds[i]))
    const res = await compareRole(user.roleId, curUser.roleId)
    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  // 验证部门ID的合法性
  const b3 = await dumpCheck.checkDepPids(
    departments.map((item) => item.departmentId),
    false
  )
  if (!b3) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 验证对应的在部门设置的角色的合法性
  const b4 = await dumpCheck.checkRoleIds(
    [...new Set(departments.map((item) => item.roleId))],
    true,
    false,
    1
  )
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  // 说明没有问题了，可以添加用户-部门记录
  // 如果记录存在，则为更新
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量设置部门空间的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.setUserDepsSizeMaxValidate = async (ctx, next) => {
  const schema = Joi.object({
    curDepId: userDepSchema.departmentId.required(),
    userIds: userDepSchema.userDepIds.required(),
    sizeMax: userDepSchema.sizeMax.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { userIds, curDepId } = ctx.request.body

  const userDeps = await UserDepartment.findAll({
    where: {
      departmentId: BigInt(curDepId),
      userId: {
        [Op.in]: userIds
      }
    }
  })

  const userDepIds = userDeps.map((item) => item.id)

  // 验证用户-部门ID数组的合法性
  const b4 = await dumpCheck.checkUserDepIds(userDepIds)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.USER_DEP_ID_ERROR)
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 将已有用户从指定部门删除
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delUserDepsValidate = async (ctx, next) => {
  const schema = Joi.object({
    userDepIds: userDepSchema.userDepIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // 要想从之前的部门删除，前提得存储用户-部门记录
  const { userDepIds } = ctx.request.body

  // 验证用户-部门ID数组的合法性
  const b4 = await dumpCheck.checkUserDepIds(userDepIds)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.USER_DEP_ID_ERROR)
    return
  }

  // 需要确保被删除用户的角色小于当前操作用户
  const userDeps = await UserDepartment.findAll({
    where: {
      id: {
        [Op.in]: userDepIds
      }
    }
  })

  // 验证userIds的合法性
  const curUser = await User.findByPk(BigInt(ctx.user.id))
  for (let i = 0; i < userDeps.length; i++) {
    const user = await User.findByPk(BigInt(userDeps[i].userId))
    const res = await compareRole(user.roleId, curUser.roleId)
    if (!res) {
      ctx.body = R.error(ERROR_SYSTEM_CODE.PERMISSION_ERROR)
      return
    }
  }

  await next()
}
